use super::traits::Item;
use super::{ErrInfo, Node};
use std::convert::From;
use std::{error::Error, fmt, rc::Rc};

pub enum XErr {
    NotExists,
    AlreadyExists,
    Unknown,
}

impl fmt::Display for XErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            XErr::NotExists => write!(f, "Not Exists!"),
            XErr::AlreadyExists => write!(f, "Key/Value Already Exists!"),
            XErr::Unknown => write!(f, "Unknown Error!"),
        }
    }
}

impl fmt::Debug for XErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Error for XErr {
    fn description(&self) -> &str {
        match self {
            XErr::NotExists => "Not Exists!",
            XErr::AlreadyExists => "Key/Value Already Exists!",
            XErr::Unknown => "Unknown Error!",
        }
    }

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

pub enum ZErr<T: Item, V> {
    NotExists(ErrInfo<T, V>), // 返回插入新值所需的必要信息
    NoValue(Rc<Node<T, V>>), // 节点存在，但是值为空，即目标节点是一个纯分支节点
    AlreadyExists(Rc<Node<T, V>>),
    Unknown,
}

impl<T: Item, V> fmt::Display for ZErr<T, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ZErr::NotExists(_) => write!(f, "Not Exists!"),
            ZErr::NoValue(_) => write!(f, "Key Exists, But Value Is Empty!"),
            ZErr::AlreadyExists(_) => write!(f, "Key/Value Already Exists!"),
            ZErr::Unknown => write!(f, "Unknown Error!"),
        }
    }
}

impl<T: Item, V> fmt::Debug for ZErr<T, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl<T: Item, V> Error for ZErr<T, V> {
    fn description(&self) -> &str {
        match self {
            ZErr::NotExists(_) => "Not Exists!",
            ZErr::NoValue(_) => ("Key Exists, But Value Is Empty!"),
            ZErr::AlreadyExists(_) => "Key/Value Already Exists!",
            ZErr::Unknown => "Unknown Error!",
        }
    }

    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

impl<T: Item, V> From<ZErr<T, V>> for XErr {
    fn from(error: ZErr<T, V>) -> Self {
        match error {
            ZErr::NotExists(_) => XErr::NotExists,
            ZErr::NoValue(_) => XErr::NotExists,
            ZErr::AlreadyExists(_) => XErr::AlreadyExists,
            ZErr::Unknown => XErr::Unknown,
        }
    }
}
